package cc.rengu.igas.channel.alipay.core.realize.impl;

import cc.rengu.igas.channel.alipay.common.constant.AlipayParamConstant;
import cc.rengu.igas.channel.alipay.common.enums.AlgorithmTypeEnum;
import cc.rengu.igas.channel.alipay.core.realize.AlipaySignService;
import cc.rengu.oltp.service.common.entity.CertInfo;
import cc.rengu.oltp.service.realize.HsmService;
import cc.rengu.oltp.service.realize.impl.HsmServiceImpl;
import cc.rengu.oltp.utility.util.RSAUtil;
import cc.rengu.utility.cache.UnifiedCache;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import org.apache.commons.codec.binary.Base64;

import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.List;

/**
 * 签名服务实现
 */
public class AlipaySignServiceImpl implements AlipaySignService {
    private static final String algorRSA = "SHA1WithRSA";
    private static final String algorRSA2 = "SHA256WithRSA";
    private static final String charset = "UTF-8";
    private RgLogger rgLog = RgLog.getLogger(this.getClass().getName());

    @Override
    public String generateSignString(String signData, CertInfo certInfo) throws Exception {
        RSAPrivateKey privateKey = null;
        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            if (certInfo.getAlgorithmType() != null && certInfo.getAlgorithmType().contains(AlgorithmTypeEnum.RSA.getTypeCode())) {
                privateKey = RSAUtil.getPrivateKeyFromBase64String(certInfo.getCertValue());
                return RSAUtil.generateSignString(signData, privateKey, (null == certInfo.getAlgorithmType()) ? algorRSA2 : certInfo.getAlgorithmType(), charset);
            } else {
                rgLog.debug("不支持加密算法类型AlgorithmType:<{}>,", certInfo.getAlgorithmType());
                return null;
            }

        } else if ("1".equals(certInfo.getCertSaveType())) {
            //调用加密机需自己客户化
            String algorithmType = "SM3";//加密机默认国密摘要
            rgLog.debug("使用加密机加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            if (certInfo.getAlgorithmType() != null) {
                if (certInfo.getAlgorithmType().contains("SHA256")) {
                    algorithmType = "SHA256";
                } else if (certInfo.getAlgorithmType().contains("RSA")) {
                    algorithmType = "SHA1";
                }
            }
            HsmService hsmService = new HsmServiceImpl();
            return hsmService.hsmGenerateSignString(null, certInfo.getCertId(), signData, algorithmType);
        } else if ("2".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            /*优先从系统缓存读取*/
            String priKeyStr = (String) UnifiedCache.get(AlipayParamConstant.CERT_KEY_CACHE, certInfo.getCertIndex());
            if (priKeyStr != null) {
                privateKey = RSAUtil.getPrivateKeyFromBase64String(priKeyStr);
            } else {
                /*从本地证书文件获取*/
                List<String> aliasList = RSAUtil.getCertAliasFromPfxCertFile(certInfo.getCertSavePath(), certInfo.getCertPassword());
                privateKey = RSAUtil.getPrivateKeyFromCertFile(certInfo.getCertSavePath(), aliasList.get(0), certInfo.getCertPassword());
                if (privateKey != null) {
                    if (UnifiedCache.set(AlipayParamConstant.CERT_KEY_CACHE, certInfo.getCertIndex(), Base64.encodeBase64String(privateKey.getEncoded())) != 0) {
                        rgLog.error("设置证书缓存索引号{}缓存失败", certInfo.getCertIndex());
                    }
                }
            }
            if (privateKey != null) {
                return RSAUtil.generateSignString(signData, privateKey, certInfo.getAlgorithmType(), charset);
            } else {
                return null;
            }

        } else {
            rgLog.debug("不支持密钥存储类型CertSaveType:<{}>,", certInfo.getCertSaveType());
            return null;
        }
    }

    @Override
    public boolean verifySignString(String sign, String signBlock, CertInfo certInfo) throws Exception {
        RSAPublicKey publicKey = null;
        // 判断证书/密钥类型,通过软加密还是硬加密方式（0-本地数据库存储,1-加密机,2-本地文件）
        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            publicKey = RSAUtil.getPublicKeyFromBase64String(certInfo.getCertValue());
            return RSAUtil.verifySignString(signBlock, sign, publicKey, (null == certInfo.getAlgorithmType()) ? algorRSA2 : certInfo.getAlgorithmType(), charset);
        } else if ("1".equals(certInfo.getCertSaveType())) {
            String algorithmType = "SM3";//加密机默认国密摘要
            rgLog.debug("使用加密机加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            if (certInfo.getAlgorithmType() != null) {
                if (certInfo.getAlgorithmType().contains("SHA256")) {
                    algorithmType = "SHA256";
                } else if (certInfo.getAlgorithmType().contains("RSA")) {
                    algorithmType = "SHA1";
                }
            }
            HsmService hsmService = new HsmServiceImpl();
            return hsmService.hsmVerifySignString(null, certInfo.getCertId(), signBlock, algorithmType, sign);
        } else if ("2".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            /*优先从系统缓存读取*/
            String pubKeyStr = (String) UnifiedCache.get(AlipayParamConstant.CERT_KEY_CACHE, certInfo.getCertIndex());
            if (pubKeyStr != null) {
                publicKey = RSAUtil.getPublicKeyFromBase64String(pubKeyStr);
            } else {
                /*从本地证书文件获取*/
                publicKey = RSAUtil.getPublicKeyFromCertFile(certInfo.getCertSavePath());
                if (publicKey != null) {
                    if (UnifiedCache.set(AlipayParamConstant.CERT_KEY_CACHE, certInfo.getCertIndex(), Base64.encodeBase64String(publicKey.getEncoded())) != 0) {
                        rgLog.error("设置证书缓存索引号{}缓存失败", certInfo.getCertIndex());
                    }
                }
            }
            if (publicKey != null) {
                return RSAUtil.verifySignString(signBlock, sign, publicKey, certInfo.getAlgorithmType(), charset);
            } else {
                return false;
            }
        }
        return false;
    }
}
